import { Middleware, IMiddleware, Inject } from '@midwayjs/core';
import { NextFunction, Context } from '@midwayjs/koa';
import { Decrypt } from '@/utils/aes'; // Decrypt
import { RedisService } from '@midwayjs/redis';
import { RedisEnum } from '@utils/enum';

// 加密白名单
const whiteList = ['/', '/captchaImage', '/public', '/logout'];

@Middleware()
export class EncryptMiddleware implements IMiddleware<Context, NextFunction> {
  @Inject()
  redisService: RedisService;

  resolve() {
    return async (ctx: Context, next: NextFunction) => {
      // 获取路由地址
      const routerUrl = ctx.request.url.split('?')[0];

      // 如果白名单，直接放行, 或者包含导入导出接口，因为导入导出是流式数据，不用加密，上传等接口
      if (
        whiteList.includes(routerUrl) ||
        routerUrl.includes('/importData') ||
        routerUrl.includes('/export') ||
        routerUrl.includes('/profile/avatar')
      ) {
        await next();
      } else {
        const temp = await this.redisService.get(
          `${RedisEnum.SYS_CONFIG_KEY}sys.interface.enable`
        );
        const isOpenCrypt = temp === null ? true : JSON.parse(temp);

        // 请求方式
        const requestMethod = ctx.method.toUpperCase();
        // 如果开启了加密（这里即便开启加密，也按不加密返回逻辑处理，若要彻底不用加密逻辑，可删除isOpenCrypt相关判断）
        if (isOpenCrypt) {
          if (requestMethod === 'GET') {
            await next();
            // 注释掉加密返回的代码，直接返回原本的响应体
            // ctx.response.body = Encrypt(JSON.stringify(ctx.response.body));
          } else if (['POST', 'PUT'].includes(requestMethod)) {
            const body: any = ctx.request.body;
            // post、put等，若前端传了加密参数仍尝试解密（如果不需要解密也可删除这行）
            if (body?.param) {
              ctx.request.body = JSON.parse(Decrypt(body?.param));
            }
            await next();
            // 注释掉加密返回的代码，直接返回原本的响应体
            // ctx.response.body = Encrypt(JSON.stringify(ctx.response.body));
          } else {
            // DELETE等其他方式，直接next
            await next();
          }
        } else {
          if (['POST', 'PUT'].includes(requestMethod)) {
            const body: any = ctx.request.body;
            // post、put等，若前端传了加密参数仍尝试解密（如果不需要解密也可删除这行）
            if (body?.param) {
              ctx.request.body = JSON.parse(Decrypt(body?.param));
            }
            await next();
          } else {
            // DELETE等其他方式，直接next
            await next();
          }
        }
      }
    };
  }

  static getName(): string {
    return 'encrypt';
  }
}
